/**
 * www.easyplatform.cn ©2016
 */
package cn.easyplatform.studio.web.editors.entity;

import cn.easyplatform.entities.beans.LogicBean;
import cn.easyplatform.entities.beans.table.TableBean;
import cn.easyplatform.entities.beans.table.TableField;
import cn.easyplatform.lang.Strings;
import cn.easyplatform.studio.StudioApp;
import cn.easyplatform.studio.cmd.entity.GetEntityCmd;
import cn.easyplatform.studio.context.Contexts;
import cn.easyplatform.studio.utils.WebUtils;
import cn.easyplatform.studio.vos.ArgsVo;
import cn.easyplatform.studio.vos.FunctionVo;
import cn.easyplatform.studio.web.editors.AbstractEntityEditor;
import cn.easyplatform.studio.web.editors.BandboxCallback;
import cn.easyplatform.studio.web.editors.CodeEditor;
import cn.easyplatform.studio.web.editors.view.Funcs;
import cn.easyplatform.studio.web.layout.WorkbenchController;
import cn.easyplatform.studio.web.views.impl.AbstractView;
import cn.easyplatform.type.EntityType;
import cn.easyplatform.web.ext.cmez.CMeditor;
import cn.easyplatform.web.ext.cmez.DropEvent;
import com.alibaba.druid.support.logging.Log;
import com.alibaba.druid.support.logging.LogFactory;
import org.zkoss.util.resource.Labels;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.Executions;
import org.zkoss.zk.ui.event.Event;
import org.zkoss.zk.ui.event.Events;
import org.zkoss.zk.ui.event.KeyEvent;
import org.zkoss.zk.ui.event.OpenEvent;
import org.zkoss.zkmax.zul.Scrollview;
import org.zkoss.zul.*;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * @author <a href="mailto:shiny_vc@163.com">陈云亮</a> <br/>
 * @since 2.0.0 <br/>
 */
public class LogicEntityEditor extends AbstractEntityEditor<LogicBean>
        implements CodeEditor {

    private final static Log log = LogFactory.getLog("LogicEntityEditor");

//    private Set<String> nameSet;

    private Textbox entityId;

    private Textbox entityName;

    private Textbox entityDesp;

    private Bandbox search;

    private Popup hint;

    private Funcs funcs;

//    private Bandbox method_search;
//
//    private Listbox listbox_catalog;
//
//    private Scrollview scrollview_content;
//
//    private Combobox combobox_catalog;
//
//    private Comboitem comboitem_all;

//    private cn.easyplatform.web.ext.zul.Include funcs;

    /**
     * @param workbench
     * @param entity
     * @param code
     */
    public LogicEntityEditor(WorkbenchController workbench, LogicBean entity,
                             char code) {
        super(workbench, entity, code);
    }

    @Override
    public void create(Object... args) {
        super.create(args);
        Tabpanel tabpanel = new Tabpanel();
        tabpanel.setCtrlKeys("@q");
        tabpanel.addEventListener(Events.ON_CTRL_KEY, this);
        Idspace is = new Idspace();
        is.setHflex("1");
        is.setVflex("1");
        is.setParent(tabpanel);
        Executions.createComponents("~./include/editor/entity/logic.zul", is,
                null);
        for (Component comp : is.getFellows()) {
            if (comp.getId().equals("logic_textbox_id")) {
                entityId = (Textbox) comp;
                entityId.setValue(entity.getId());
                entityId.setReadonly(true);
            } else if (comp.getId().equals("logic_textbox_name")) {
                entityName = (Textbox) comp;
                comp.addEventListener(Events.ON_CHANGE, this);
                entityName.setValue(entity.getName());
            } else if (comp.getId().equals("logic_textbox_desp")) {
                entityDesp = (Textbox) comp;
                comp.addEventListener(Events.ON_CHANGE, this);
                entityDesp.setValue(entity.getDescription());
            } else if (comp.getId().equals("logic_cmeditor_editor")) {
                source = (CMeditor) comp;
                source.setTheme(Contexts.getUser().getEditorTheme());
                source.setValue(entity.getContent());
                source.setDroppable(EntityType.TABLE.getName());
                source.addEventListener(Events.ON_DROP, this);
                source.addEventListener(Events.ON_CHANGING, this);
                source.addEventListener(CMeditor.ON_CURSOR_ACTIVITY, this);
            } else if (comp.getId().equals("logic_bandbox_search")) {
                search = (Bandbox) comp;
                search.addEventListener(Events.ON_CHANGE, this);
                search.addEventListener(Events.ON_OK, this);
                search.addEventListener(Events.ON_OPEN, this);
            } else if (comp.getId().equals("logic_popup_hint")) {
                hint = (Popup) comp;
//            } else if (comp.getId().equals("logic_scrollview_method_content")) {
//                scrollview_content = (Scrollview) comp;
//            } else if (comp.getId().equals("logic_listbox_method_catalog")){
//                listbox_catalog = (Listbox) comp;
////                listbox_catalog.setDraggable(EntityType.TABLE.getName());
//                listbox_catalog.addEventListener(Events.ON_CLICK, this);
////                listbox_catalog.addEventListener(Events.ON_DROP, this);
//            } else if (comp.getId().equals("logic_combobox_catalog")){
//                combobox_catalog = (Combobox)comp;
//                combobox_catalog.addEventListener(Events.ON_CHANGE, this);
//            } else if (comp.getId().equals("logic_bandbox_method_search")){
//                method_search = (Bandbox)comp;
//                method_search.addEventListener(Events.ON_CHANGE, this);
//                method_search.addEventListener(Events.ON_OK, this);
//                method_search.addEventListener(Events.ON_OPEN, this);
//            } else if(comp.getId().equals("logic_comboitem_all")){
//                comboitem_all = (Comboitem)comp;
            } else if(comp.getId().equals("functionsInc")){
                funcs = new Funcs((cn.easyplatform.web.ext.zul.Include)comp, "450px");
//                comboitem_all = (Comboitem)funcs.getFellow("logic_comboitem_all");
//                scrollview_content = (Scrollview)funcs.getFellow("logic_scrollview_method_content");
//                method_search = (Bandbox)funcs.getFellow("logic_bandbox_method_search");
//                method_search.addEventListener(Events.ON_CHANGE, this);
//                method_search.addEventListener(Events.ON_OK, this);
//                method_search.addEventListener(Events.ON_OPEN, this);

//                listbox_catalog = (Listbox) funcs.getFellow("logic_listbox_method_catalog");
//                listbox_catalog.addEventListener(Events.ON_CLICK, this);
//
//                combobox_catalog = (Combobox)funcs.getFellow("logic_combobox_catalog");
//                combobox_catalog.addEventListener(Events.ON_CHANGE, this);
//
//                comboitem_all = (Comboitem)funcs.getFellow("logic_comboitem_all");
//                comboitem_all = (Comboitem)funcs.getFellow("logic_comboitem_all");

                this.log.debug("functionsInc");
            } else {
                //this.log.debug("");
            }
        }
        if (args.length > 0) {
            String table = (String) args[0];
            if (!Strings.isBlank(table)) {
                search.setValue(table);
                showTable();
            }
        }
        workbench.addEditor(tab, tabpanel);
    }

    @Override
    protected boolean validate() {
        if (Strings.isBlank(entity.getName())) {
            WebUtils.notEmpty(Labels.getLabel("entity.name"));
            return false;
        }
        if (Strings.isBlank(entity.getContent())) {
            WebUtils.notEmpty(Labels.getLabel("editor.report.content"));
            return false;
        }
        return true;
    }

    @SuppressWarnings("unchecked")
    @Override
    protected void dispatch(Event evt) {
        if (evt.getTarget() == search) {
            if (evt.getName().equals(Events.ON_OPEN)||evt instanceof KeyEvent) {
                if (evt instanceof OpenEvent){
                    search.setValue(((OpenEvent)evt).getValue()+"");
                }
                AbstractView.createEntityView(
                        new BandboxCallback(this, search),
                        EntityType.TABLE.getName(), search).doOverlapped();
            } else
                showTable();
        } else if (evt.getName().equals(Events.ON_CTRL_KEY)) {
            format();
        } else if (evt.getName().equals(CMeditor.ON_CURSOR_ACTIVITY)) {
            showHint((Map<String, Object>) evt.getData(), source.getValue().toString());
        } else if (evt.getName().equals(Events.ON_CHANGE)
                || evt.getName().equals(Events.ON_CHANGING)) {
            Component c = evt.getTarget();
            if (c == entityName) {
                entity.setName(entityName.getValue());
                setDirty();
            } else if (c == entityDesp) {
                entity.setDescription(entityDesp.getValue());
                setDirty();
//            } else if(c == combobox_catalog){
//                showCatalog((String)combobox_catalog.getSelectedItem().getValue());
//                refreshListbox();
            } else {
                entity.setContent((String) source.getValue());
                setDirty();
            }
        } else if (evt.getName().equals(Events.ON_DROP)) {
            doDrop((DropEvent) evt);
//        } else if(evt.getTarget() == method_search){
//            if (evt.getName().equals(Events.ON_OPEN)||evt instanceof KeyEvent) {
//                if (evt instanceof OpenEvent){
//                    method_search.setValue(((String)((OpenEvent)evt).getValue()).trim());
//                }
//                combobox_catalog.setSelectedItem(comboitem_all);
//                showCatalog(method_search.getValue());
//                refreshListbox();
//            }
//        } else if(evt.getTarget() == listbox_catalog){
//            showContent();
        }
    }

    private void showTable() {
        Group group = (Group) search.getParent();
        Rows rows = group.getGrid().getRows();
        rows.getChildren().removeAll(group.getItems());
        if (search.getValue().trim().equals(""))
            return;
        TableBean e = (TableBean) StudioApp.execute(null, new GetEntityCmd(
                search.getValue().trim()));
        if (e != null && e.getFields() != null) {
            for (TableField tf : e.getFields()) {
                Row row = new Row();
                row.setValue(tf);
                row.setDraggable(EntityType.TABLE.getName());
                row.appendChild(new Label(tf.getName()));
                row.appendChild(new Label(tf.getDescription()));
                row.setParent(rows);
            }
        }
        group.setOpen(true);
    }

    private void doDrop(DropEvent evt) {
//        String[] content = source.getValue().toString().split("\n");
//        StringBuilder sb = new StringBuilder();
        if(evt.getDragged() instanceof Row) {
            Row row = (Row) evt.getDragged();
            TableField tf = row.getValue();
            String text = (row.getRoot() == source.getRoot() ? "$" : "@")
                    + tf.getName();
            source.insertText(evt.getLine(), evt.getCh(), text);
        } else if(evt.getDragged() instanceof Listitem) {
            Listitem row = (Listitem) evt.getDragged();
            String text = row.getValue();
            FunctionVo fv = StudioApp.getFunctionDesc(text);
            source.insertText(evt.getLine(), evt.getCh(), text + fv.getExp());
            StringBuilder sb = new StringBuilder();
            createHint(sb, fv, 0, 0);
        }
        setDirty();
    }

    public void showHint(Map<String, Object> objs, String editorContent) {
        int line = (Integer) objs.get("line");
        int ch = (Integer) objs.get("ch");
        //String[] content = source.getValue().toString().split("\n");
        String[] content = editorContent.split("\n");
        if (line >= content.length)
            return;
        char[] cs = content[line].toCharArray();
        if (ch >= cs.length)
            return;
        StringBuilder sb = new StringBuilder();
        String prefix = null;
        for (int pos = ch - 1; pos >= 0; pos--) {
            if (!Character.isLetterOrDigit(cs[pos])) {
                if (cs[pos] == '.') {
                    sb.reverse();
                    prefix = sb.toString();
                    sb.setLength(0);
                    continue;
                } else {
                    if (cs[pos] == '#' && prefix != null)
                        sb.append(cs[pos]);
                    break;
                }
            }
            sb.append(cs[pos]);
        }
        sb.reverse();
        String target = null;
        if (prefix == null)
            target = "";
        else {
            target = sb.toString();
            sb.setLength(0);
        }
        sb.append(prefix == null ? "" : prefix);
        for (int pos = ch; pos < cs.length; pos++) {
            if (!Character.isLetterOrDigit(cs[pos])) {
                if (cs[pos] != '(')
                    sb.setLength(0);
                break;
            }
            sb.append(cs[pos]);
        }
        String suffix = sb.toString();
        sb.setLength(0);
        if (Strings.isBlank(target)) {
            if (!Strings.isBlank(suffix)) {
                FunctionVo vo = StudioApp.getFunctionDesc(suffix);
                if (vo != null && hint != null)
                    createHint(sb, vo, ((Number) objs.get("left")).intValue(),
                            ((Number) objs.get("top")).intValue());
            }
        } else if (!Strings.isBlank(suffix)) {
            FunctionVo vo = StudioApp.getFunctionDesc(target + "." + suffix);
            if (vo != null && hint != null)
                createHint(sb, vo, ((Number) objs.get("left")).intValue(),
                        ((Number) objs.get("top")).intValue());
        }
    }

    public void createHint(StringBuilder sb, FunctionVo vo, int left, int top) {
        StringBuffer newsb = new StringBuffer();
        sb.append("<ul class=\"list-group\">");
        if (vo.getArgs() != null) {
            for (ArgsVo av : vo.getArgs()) {
                sb.append("<li class=\"list-group-item\">");
                sb.append("<h4 class=\"list-group-item-heading\">")
                        .append(vo.getName()).append(av.getName())
                        .append("</h4>");
                sb.append("<p class=\"list-group-item-text\">")
                        .append(av.getDesc()).append("</p>");
                sb.append("</li>");
                newsb.append(vo.getName()+"."+av.getName()+ "\n");
                newsb.append(av.getDesc()+ "\n"+ "\n");
            }
        }
        if (vo.getExamples() != null) {
            for (String s : vo.getExamples()) {
                sb.append("<li class=\"list-group-item\">");
                String[] cs = s.split("\n");
                for (int i = 0; i < cs.length; i++) {
                    if (!cs[i].trim().equals("")) {
                        cs[i] = cs[i].replaceFirst("\t", "");
                        sb.append(cs[i].replaceAll("\t", "&emsp;"));
                        if (i < cs.length - 1)
                            sb.append("</br>");
                    }
                }
                sb.append("</li>");
                newsb.append(s);
            }
        }
        sb.append("</ul>");
        Html html = (Html) hint.getFirstChild();
        if (html == null) {
            html = new Html();
            hint.appendChild(html);
        }
        html.setContent(sb.toString());
        Label hintLab = new Label();
        hintLab.setValue(newsb.toString());
        hintLab.setStyle("font-size:14px;color:#333333;white-space:pre-wrap");
        Div hintDiv = new Div();
        hintDiv.appendChild(hintLab);

        funcs.updateScroll(hintDiv);
    }

    public void setHint(Popup hint) {
        this.hint = hint;
    }

    @Override
    public void insertTodo() {
        source.insertText("//TODO");
    }

    @Override
    public void insertComments() {
        source.insertText("/* This is a comment */");
    }

    @Override
    public void undo() {
        source.exeCmd("undo");
    }

    @Override
    public void redo() {
        source.exeCmd("redo");
    }

    @Override
    public void selectAll() {
        source.exeCmd("selectAll");
    }

    @Override
    public void format() {
        source.exeCmd("format");
    }

    @Override
    public void formatAll() {
        source.exeCmd("formatAll");
    }

    @Override
    public void deleteLine() {
        source.exeCmd("deleteLine");
    }

    @Override
    public void indentMore() {
        source.exeCmd("indentMore");
    }

    @Override
    public void indentLess() {
        source.exeCmd("indentLess");
    }

    @Override
    public void find() {
        source.exeCmd("find");
    }

    @Override
    public void findNext() {
        source.exeCmd("findNext");
    }

    @Override
    public void findPrev() {
        source.exeCmd("findPrev");
    }

    @Override
    public void replace() {
        source.exeCmd("replace");
    }

    @Override
    public void replaceAll() {
        source.exeCmd("replaceAll");
    }
}
